//
//  GameManager.swift
//  I Hate Duck
//
//  Created by Leonard Chen on 8/22/19.
//  Copyright © 2019 Leonard Chan. All rights reserved.
//

import Foundation
import SpriteKit

class GameManager {
    unowned var scene: SKScene!
  
    var totalScore = 0
    let targetScore = 10
    let duckScore = 10
    
    var duckCount = 0
    var targetCount = 0
    
    var duckMoveDuration: TimeInterval!
    var timer1 : Timer!
    var timer2 : Timer!
    var timer3 : Timer!
    
    let targetXPosition: [Int] = [160, 240, 320, 400, 480, 560, 640]
    var usingTargetXPosition = Array<Int>()
    
    // The amount of ammunition
    var ammunitionQuantity = 5
    
    var numExitTimes = 3
    var life = 3
    
    var zPositionDecimal = 0.00001 {
        didSet {
            if zPositionDecimal == 1 {
               zPositionDecimal = 0.00001
            }
        }
    }
    
    init(scene: SKScene) {
        self.scene = scene
    }
    
    func generateDuck(hasTarget: Bool = false) -> Duck {
        var duck: SKSpriteNode

        var duckImageName: String
        var duckNodeName: String
      
        var node = Duck()
        var texture = SKTexture()
        
        if hasTarget {
            duckImageName = "duck_target/\(Int.random(in: 1...3))"
            texture = SKTexture(imageNamed: duckImageName)
            duckNodeName = "duck_target"
            node = Duck(hasTarget: true)
        } else {
            duckImageName = "duck/\(Int.random(in: 1...3))"
            texture = SKTexture(imageNamed: duckImageName)
            duckNodeName = "duck"
            node = Duck()
        }
        
        duck = SKSpriteNode(texture: texture)
        duck.name = duckNodeName
        duck.position = CGPoint(x: 0, y: 140)
        
        let physicsBody = SKPhysicsBody(texture: texture, alphaThreshold: 0.5, size: texture.size())
        physicsBody.affectedByGravity = false
        physicsBody.isDynamic = false
        duck.physicsBody = physicsBody
        
        duck.setScale(CGFloat(Double.random(in: 0.8...1.1)))
        node.addChild(duck)
        return node
    }
    
    func dieDuck() -> DieDuck {
        
        var dieDuck: SKSpriteNode
        var duckImageName: String
        var duckNodeName: String
        var node = DieDuck()
        var texture = SKTexture()
        
        
        duckImageName = "die"
        texture = SKTexture(imageNamed: duckImageName)
        duckNodeName = "die"
        node = DieDuck()
        
        
        dieDuck = SKSpriteNode(texture: texture)
        dieDuck.name = duckNodeName
        dieDuck.position = CGPoint(x: 0, y: 140)
        
        
        let diePhysicsBody = SKPhysicsBody(texture: texture, alphaThreshold: 0.5, size: texture.size())
        diePhysicsBody.affectedByGravity = false
        diePhysicsBody.isDynamic = false
        dieDuck.physicsBody = diePhysicsBody
        
        
        dieDuck.setScale(CGFloat(Double.random(in: 0.8...1.3)))
        node.addChild(dieDuck)
        return node
    }
    
    func generateTarget() -> Target {
        var target: SKSpriteNode
        let node = Target()
        let texture = SKTexture(imageNamed: "target/\(Int.random(in: 1...3))")
        
        target = SKSpriteNode(texture: texture)

        target.setScale(CGFloat(Double.random(in: 0.8...1.1)))
        target.position = CGPoint(x: 0, y: 95)
        target.name = "target"
        
        node.addChild(target)
        
        return node
    }
 
    func activeDucks() {
        self.timer1 = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer)  in
            let duck = self.generateDuck(hasTarget: Bool.random())
            duck.position = CGPoint(x: -10, y: Int.random(in: 35...90))
            duck.zPosition = Int.random(in: 0...1) == 0 ? 4 : 6
            duck.zPosition = duck.zPosition + CGFloat(self.zPositionDecimal)
            self.zPositionDecimal += 0.00001
            self.scene.addChild(duck)
            if duck.hasTarget {
                self.duckMoveDuration = TimeInterval(Int.random(in: 2...4))
            } else {
                self.duckMoveDuration = TimeInterval(Int.random(in: 5...7))
            }
            
            duck.run(.sequence([
                .moveTo(x: 850, duration: self.duckMoveDuration),
                .removeFromParent()]))
        }
    }

    func exitTimes() {
        if numExitTimes != 0{
            numExitTimes -= 1
        }else{
            self.timer1.invalidate()
            self.timer1 = nil
            self.timer2.invalidate()
            self.timer2 = nil
            self.timer3.invalidate()
            self.timer3 = nil
        }
    }
 
    func activeDie(){
        self.timer2 = Timer.scheduledTimer(withTimeInterval: TimeInterval(Int.random(in: 1...3)), repeats: true) { (timer) in
            let dieDuck = self.dieDuck()
            dieDuck.position = CGPoint(x: -10, y: Int.random(in: 35...90))
            dieDuck.zPosition = 6
            dieDuck.zPosition = dieDuck.zPosition + CGFloat(self.zPositionDecimal)
            self.zPositionDecimal += 0.01
            self.scene.addChild(dieDuck)
            self.duckMoveDuration = TimeInterval(Double.random(in: 0.7...2.7))
            
            dieDuck.run(.sequence([
                .moveTo(x: 850, duration: self.duckMoveDuration),
                .removeFromParent()]))
        }
    }
    
    func activeTargets() {
        self.timer3 = Timer.scheduledTimer(withTimeInterval: TimeInterval(Int.random(in: 2...3)), repeats: true) { (timer) in
            let target = self.generateTarget()
            var xPosition = self.targetXPosition.randomElement()!
            while self.usingTargetXPosition.contains(xPosition) {
                xPosition = self.targetXPosition.randomElement()!
            }
            
            self.usingTargetXPosition.append(xPosition)
            target.position = CGPoint(x: xPosition, y: Int.random(in: 120...195))
            target.zPosition = 1
            target.yScale = 0
            self.scene.addChild(target)
            
            let physicsBody = SKPhysicsBody(circleOfRadius: 71/2)
            physicsBody.affectedByGravity = false
            physicsBody.isDynamic = false
            physicsBody.allowsRotation = false
            
            target.run(.sequence([
                .scaleY(to: 1, duration: 0.2),
                .run {
                    if let node = target.childNode(withName: "target") {
                        node.physicsBody = physicsBody
                    }
                },
                .wait(forDuration: TimeInterval(Int.random(in: 3...6))),
                .scaleY(to: 0, duration: 0.2),
                .removeFromParent(),
                .run {
                    self.usingTargetXPosition.remove(at: self.usingTargetXPosition.firstIndex(of: xPosition)!)
                }]))
        }
    }
    
    func generateTextNode(from text: String, leadingAnchorPoint: Bool = true) -> SKNode {
        let node = SKNode()
        var width: CGFloat = 0.0
        for character in text {
            var characterNode = SKSpriteNode()
            if character == "0" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.zero.textureName)
            } else if character == "1" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.one.textureName)
            } else if character == "2" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.two.textureName)
            } else if character == "3" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.three.textureName)
            } else if character == "4" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.four.textureName)
            } else if character == "5" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.five.textureName)
            } else if character == "6" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.six.textureName)
            } else if character == "7" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.seven.textureName)
            } else if character == "8" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.eight.textureName)
            } else if character == "9" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.nine.textureName)
            } else if character == "+" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.plus.textureName)
            } else if character == "*" {
                characterNode = SKSpriteNode(imageNamed: ScoreNumber.multiplication.textureName)
            } else {
                continue
            }
               node.addChild(characterNode)
           
            characterNode.anchorPoint = CGPoint(x: 0, y: 0.5)
            characterNode.position = CGPoint(x: width, y: 0.0)
            width += characterNode.size.width
        }
       
        if leadingAnchorPoint {
            return node
        } else {
            let anotherNode = SKNode()
            anotherNode.addChild(node)
            node.position = CGPoint(x: -width/2, y: 0)
            return anotherNode
        }
    }
    
    func update(text: String, node: inout SKNode, leadingAnchorPoint: Bool = true) {
      
        let position = node.position
        let zPositon = node.zPosition
        let xScale = node.xScale
        let yScale = node.yScale
        
        node.removeFromParent()
        
        node = generateTextNode(from: text, leadingAnchorPoint: leadingAnchorPoint)
        node.position = position
        node.zPosition = zPositon
        node.xScale = xScale
        node.yScale = yScale
        scene.addChild(node)
        
    }
  
    func findShootNode(at position: CGPoint) -> SKSpriteNode {
        var shootNode = SKSpriteNode()
        var biggestZPosition: CGFloat = 0.0
        

        scene.physicsWorld.enumerateBodies(at: position) { (body, pointer) in
            guard let node = body.node as? SKSpriteNode else { return }
            
            if node.name == "duck" || node.name == "duck_target" || node.name == "target" || node.name == "die"{
                if let parentNode = node.parent {
                    if parentNode.zPosition > biggestZPosition {
                        biggestZPosition = parentNode.zPosition
                        shootNode = node
                    }
                }
            }
        }
        return shootNode
}
   
    func findTextAndImageName(for nodeName: String?) -> (String, String)? {
        var scoreText = ""
        var shotImageName = ""
        
        switch nodeName {
        case "duck":
            scoreText = "+\(duckScore)"
            totalScore += duckScore
            duckCount += 1
            shotImageName = Texture.shotblue.imageName
        case "duck_target":
            scoreText = "+\(duckScore + targetScore)"
            totalScore += duckScore + targetScore
            duckCount += 1
            targetCount += 1
            shotImageName = Texture.shotblue.imageName
        case "target":
            scoreText = "+\(targetScore)"
            totalScore += targetScore
            targetCount += 1
            shotImageName = Texture.shotblue.imageName
        case "die":
            if PlayHandler.sharedInstance.isPlay {
                CJDPlayerHandler.sharedInstance.play(fileName: "warning", vol: 1.3, numberOfLoops: 0)
            }
            shotImageName = Texture.ban.imageName
            
            life -= 1
                self.exitTimes()
            NotificationCenter.default.post(
                    name: NSNotification.Name(rawValue: "Gameover"),
                    object: self,
                    userInfo: nil)
            
        default:
            return nil
        }
            return (scoreText, shotImageName)
    }

    func addShot(imageNamed imageName: String, to node: SKSpriteNode, on position: CGPoint) {
        let convertedPosition = scene.convert(position, to: node)
        let shot = SKSpriteNode(imageNamed: imageName)
        shot.position = convertedPosition
        node.addChild(shot)
        shot.run(.sequence([
            .wait(forDuration: 2),
            .fadeAlpha(to: 0.0, duration: 0.3),
            .removeFromParent()]))
    }
    
    func addTextNode(on position: CGPoint, from text: String) {
        let scorePosition = CGPoint(x: position.x + 10, y: position.y + 30)
        let scoreNode = generateTextNode(from: text)
        scoreNode.position = scorePosition
        scoreNode.zPosition = 9
        scoreNode.xScale = 0.5
        scoreNode.yScale = 0.5
        scene.addChild(scoreNode)
        scoreNode.run(.sequence([
            .wait(forDuration: 0.5),
            .fadeOut(withDuration: 0.2),
            .removeFromParent()]))
    }
    func sumCount() -> Int{
        
        return totalScore
    }
}
